package org.budo.dubbo.protocol.http.view.render.budo;

import java.io.IOException;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.budo.dubbo.protocol.http.aop.permission.user.UserPermissionCheckException;
import org.budo.dubbo.protocol.http.dispatcher.servlet.ServletProtocolResponse;
import org.budo.dubbo.protocol.http.exception.remoting.AuthenticationCheckException;
import org.budo.dubbo.protocol.http.invocation.adapter.ProtocolRequest;
import org.budo.dubbo.protocol.http.invocation.adapter.ProtocolResponse;
import org.budo.dubbo.protocol.http.view.render.impl.WebHttpJsonViewRender;
import org.budo.support.dao.page.PageModel;
import org.budo.support.exception.business.BusinessException;
import org.budo.support.lang.util.MapUtil;
import org.budo.support.slf4j.Slf4j;
import org.slf4j.Logger;

/**
 * @author limingwei
 */
public class BudoWebHttpJsonViewRender extends WebHttpJsonViewRender {
    private static final Logger log = Slf4j.getLogger();

    private ExceptionRender exceptionRender = new ExceptionRender();

    @Override
    protected void renderResultValue(ProtocolRequest protocolRequest, ProtocolResponse protocolResponse, Object rpcResultValue) throws IOException {
        Map<String, Object> map;
        if (null != rpcResultValue && rpcResultValue instanceof PageModel) {
            PageModel pageModel = (PageModel) rpcResultValue;
            Map<String, Object> pageModelMap = MapUtil.stringObjectMap("recordCount", pageModel.getRecordCount(), "list", pageModel.getList());
            map = MapUtil.stringObjectMap("status", 0, "result", pageModelMap);
        } else {
            map = MapUtil.stringObjectMap("status", 0, "result", rpcResultValue);
        }

        this.processResultValueAndSerializeAndWriteToResponse(protocolRequest, protocolResponse, map);
    }

    @Override
    protected void renderException(ProtocolRequest protocolRequest, ProtocolResponse protocolResponse, Throwable exception) throws IOException {
        this.setResponseStatus(protocolResponse, exception);

        ApiError apiError = exceptionRender.buildApiError(exception);
        this.renderDubboApiError(protocolRequest, protocolResponse, apiError);
    }

    protected void setResponseStatus(ProtocolResponse protocolResponse, Throwable exception) {
        if (exception instanceof BusinessException //
                || exception instanceof AuthenticationCheckException //
                || exception instanceof UserPermissionCheckException //
        ) {
            return; // 状态 仍然 200
        }

        this.setResponseStatus(protocolResponse, 500); // 其他异常状态 500
    }

    private void setResponseStatus(ProtocolResponse protocolResponse, Integer responseStatus) {
        if (protocolResponse instanceof ServletProtocolResponse) {
            HttpServletResponse response = ((ServletProtocolResponse) protocolResponse).getResponse();
            response.setStatus(responseStatus);
            return;
        }

        log.warn("#62 protocolResponse.type=" + protocolResponse.getClass());
    }

    protected void renderDubboApiError(ProtocolRequest protocolRequest, ProtocolResponse protocolResponse, ApiError error) throws IOException {
        Map<String, Object> result = MapUtil.stringObjectMap("error", error.getName(), //
                "error_description", error.getDescription());

        Map<String, Object> map = MapUtil.stringObjectMap("status", error.getCode(), //
                "result", result); //

        this.processResultValueAndSerializeAndWriteToResponse(protocolRequest, protocolResponse, map);
    }
}